import java.util.*;
import java.util.concurrent.*;
import java.util.stream.*;

public class PaperList {
    private final String teacher;
    private final List<Paper> papers;
    private final PaperSelection selections = new PaperSelection();
    private final Random random = new Random();
    private static final int MAX_RETRY = 3;

    public PaperList(String teacher, List<Paper> papers) {
        this.teacher = teacher;
        this.papers = Collections.unmodifiableList(new ArrayList<>(papers));
    }

    public synchronized List<Paper> selectPaperByRandom(Student student)
            throws NoEnoughPapersException {

        // 获取符合要求的未选论文
        List<Paper> availablePapers = getAvailablePapers(student);

        // 检查可用数量
        if (availablePapers.size() < student.getPreferredQuantity()) {
            throw new NoEnoughPapersException(
                    student.getName(),
                    student.getPreferredQuantity(),
                    availablePapers.size());
        }

        // 有限次重试机制
        for (int retry = 0; retry < MAX_RETRY; retry++) {
            List<Paper> selected = trySelectPapers(availablePapers, student);
            if (selected != null) {
                return selected;
            }
            availablePapers = getAvailablePapers(student); // 刷新可用论文
        }

        throw new NoEnoughPapersException(
                student.getName(),
                student.getPreferredQuantity(),
                0);
    }

    private List<Paper> getAvailablePapers(Student student) {
        return papers.stream()
                .filter(p -> !selections.isSelected(p))
                .filter(p -> student.getPreferredPaperType() == PaperType.Any ||
                        p.getClass().getSimpleName().equals(student.getPreferredPaperType().toString()))
                .collect(Collectors.toList());
    }

    private List<Paper> trySelectPapers(List<Paper> availablePapers, Student student) {
        Collections.shuffle(availablePapers);
        List<Paper> selected = availablePapers.subList(0, student.getPreferredQuantity());

        // 原子性添加选择
        if (selections.tryAddAll(student, selected)) {
            return selected;
        }
        return null;
    }

    public PaperSelection getSelectionResult() {
        return selections;
    }
}